module DE2_TOP (
    // Clock Input
    input         CLOCK_27,    // 27 MHz
    input         CLOCK_50,    // 50 MHz
    input         EXT_CLOCK,   // External Clock
    // Push Button
    input  [3:0]  KEY,         // Pushbutton[3:0]
    // DPDT Switch
    input  [17:0] SW,          // Toggle Switch[17:0]
    // 7-SEG Display
    output [6:0]  HEX0,        // Seven Segment Digit 0
    output [6:0]  HEX1,        // Seven Segment Digit 1
    output [6:0]  HEX2,        // Seven Segment Digit 2
    output [6:0]  HEX3,        // Seven Segment Digit 3
    output [6:0]  HEX4,        // Seven Segment Digit 4
    output [6:0]  HEX5,        // Seven Segment Digit 5
    output [6:0]  HEX6,        // Seven Segment Digit 6
    output [6:0]  HEX7,        // Seven Segment Digit 7
    // LED
    output [8:0]  LEDG,        // LED Green[8:0]
    output [17:0] LEDR,        // LED Red[17:0]
    // UART
    output        UART_TXD,    // UART Transmitter
    input         UART_RXD,    // UART Receiver
    // IRDA
    output        IRDA_TXD,    // IRDA Transmitter
    input         IRDA_RXD,    // IRDA Receiver
    // SDRAM Interface
    inout  [15:0] DRAM_DQ,     // SDRAM Data bus 16 Bits
    output [11:0] DRAM_ADDR,   // SDRAM Address bus 12 Bits
    output        DRAM_LDQM,   // SDRAM Low-byte Data Mask 
    output        DRAM_UDQM,   // SDRAM High-byte Data Mask
    output        DRAM_WE_N,   // SDRAM Write Enable
    output        DRAM_CAS_N,  // SDRAM Column Address Strobe
    output        DRAM_RAS_N,  // SDRAM Row Address Strobe
    output        DRAM_CS_N,   // SDRAM Chip Select
    output        DRAM_BA_0,   // SDRAM Bank Address 0
    output        DRAM_BA_1,   // SDRAM Bank Address 0
    output        DRAM_CLK,    // SDRAM Clock
    output        DRAM_CKE,    // SDRAM Clock Enable
    // Flash Interface
    inout  [7:0]  FL_DQ,       // FLASH Data bus 8 Bits
    output [21:0] FL_ADDR,     // FLASH Address bus 22 Bits
    output        FL_WE_N,     // FLASH Write Enable
    output        FL_RST_N,    // FLASH Reset
    output        FL_OE_N,     // FLASH Output Enable
    output        FL_CE_N,     // FLASH Chip Enable
    // SRAM Interface
    inout  [15:0] SRAM_DQ,     // SRAM Data bus 16 Bits
    output [17:0] SRAM_ADDR,   // SRAM Address bus 18 Bits
    output        SRAM_UB_N,   // SRAM High-byte Data Mask 
    output        SRAM_LB_N,   // SRAM Low-byte Data Mask 
    output        SRAM_WE_N,   // SRAM Write Enable
    output        SRAM_CE_N,   // SRAM Chip Enable
    output        SRAM_OE_N,   // SRAM Output Enable
    // ISP1362 Interface
    inout  [15:0] OTG_DATA,    // ISP1362 Data bus 16 Bits
    output [1:0]  OTG_ADDR,    // ISP1362 Address 2 Bits
    output        OTG_CS_N,    // ISP1362 Chip Select
    output        OTG_RD_N,    // ISP1362 Write
    output        OTG_WR_N,    // ISP1362 Read
    output        OTG_RST_N,   // ISP1362 Reset
    output        OTG_FSPEED,  // USB Full Speed, 0 = Enable, Z = Disable
    output        OTG_LSPEED,  // USB Low Speed,  0 = Enable, Z = Disable
    input         OTG_INT0,    // ISP1362 Interrupt 0
    input         OTG_INT1,    // ISP1362 Interrupt 1
    input         OTG_DREQ0,   // ISP1362 DMA Request 0
    input         OTG_DREQ1,   // ISP1362 DMA Request 1
    output        OTG_DACK0_N, // ISP1362 DMA Acknowledge 0
    output        OTG_DACK1_N, // ISP1362 DMA Acknowledge 1
    // LCD Module 16X2
    inout  [7:0]  LCD_DATA,    // LCD Data bus 8 bits
    output        LCD_ON,      // LCD Power ON/OFF
    output        LCD_BLON,    // LCD Back Light ON/OFF
    output        LCD_RW,      // LCD Read/Write Select, 0 = Write, 1 = Read
    output        LCD_EN,      // LCD Enable
    output        LCD_RS,      // LCD Command/Data Select, 0 = Command, 1 = Data
    // SD Card Interface
    inout         SD_DAT,      // SD Card Data
    inout         SD_DAT3,     // SD Card Data 3
    inout         SD_CMD,      // SD Card Command Signal
    output        SD_CLK,      // SD Card Clock
    // I2C
    inout         I2C_SDAT,    // I2C Data
    output        I2C_SCLK,    // I2C Clock
    // PS2
    input         PS2_DAT,     // PS2 Data
    input         PS2_CLK,     // PS2 Clock
    // USB JTAG link
    input         TDI,         // CPLD -> FPGA (data in)
    input         TCK,         // CPLD -> FPGA (clk)
    input         TCS,         // CPLD -> FPGA (CS)
    output        TDO,         // FPGA -> CPLD (data out)
    // VGA
    output        VGA_CLK,     // VGA Clock
    output        VGA_HS,      // VGA H_SYNC
    output        VGA_VS,      // VGA V_SYNC
    output        VGA_BLANK,   // VGA BLANK
    output        VGA_SYNC,    // VGA SYNC
    output [9:0]  VGA_R,       // VGA Red[9:0]
    output [9:0]  VGA_G,       // VGA Green[9:0]
    output [9:0]  VGA_B,       // VGA Blue[9:0]
    // Ethernet Interface
    inout  [15:0] ENET_DATA,   // DM9000A DATA bus 16Bits
    output        ENET_CMD,    // DM9000A Command/Data Select, 0 = Command, 1 = Data
    output        ENET_CS_N,   // DM9000A Chip Select
    output        ENET_WR_N,   // DM9000A Write
    output        ENET_RD_N,   // DM9000A Read
    output        ENET_RST_N,  // DM9000A Reset
    input         ENET_INT,    // DM9000A Interrupt
    output        ENET_CLK,    // DM9000A Clock 25 MHz
    // Audio CODEC
    inout         AUD_ADCLRCK, // Audio CODEC ADC LR Clock
    input         AUD_ADCDAT,  // Audio CODEC ADC Data
    inout         AUD_DACLRCK, // Audio CODEC DAC LR Clock
    output        AUD_DACDAT,  // Audio CODEC DAC Data
    inout         AUD_BCLK,    // Audio CODEC Bit-Stream Clock
    output        AUD_XCK,     // Audio CODEC Chip Clock
    // TV Decoder
    input  [7:0]  TD_DATA,     // TV Decoder Data bus 8 bits
    input         TD_HS,       // TV Decoder H_SYNC
    input         TD_VS,       // TV Decoder V_SYNC
    output        TD_RESET,    // TV Decoder Reset
    // GPIO
    inout  [35:0] GPIO_0,      // GPIO Connection 0
    inout  [35:0] GPIO_1       // GPIO Connection 1
);
   
	//Set all GPIO to tri-state.
	assign GPIO_0 = 36'hzzzzzzzzz;
	//assign GPIO_1 = 36'hzzzzzzzzz;

	//Disable audio codec.
	assign AUD_DACDAT = 1'b0;
	assign AUD_XCK    = 1'b0;

	//Disable Ethernet.
	assign ENET_CLK   = 1'b0;
	assign ENET_CS_N  = 1'b1;
	assign ENET_CMD   = 1'b0;
	assign ENET_DATA  = 16'hzzzz;
	assign ENET_RD_N  = 1'b1;
	assign ENET_RST_N = 1'b1;
	assign ENET_WR_N  = 1'b1;

	//Disable flash.
	assign FL_ADDR  = 22'h0;
	assign FL_CE_N  = 1'b1;
	assign FL_DQ    = 8'hzz;
	assign FL_OE_N  = 1'b1;
	assign FL_RST_N = 1'b1;
	assign FL_WE_N  = 1'b1;

	//Disable LCD.
	assign LCD_BLON = 1'b0;
	assign LCD_DATA = 8'hzz;
	assign LCD_EN   = 1'b0;
	assign LCD_ON   = 1'b0;
	assign LCD_RS   = 1'b0;
	assign LCD_RW   = 1'b0;

	//Disable OTG.
	assign OTG_ADDR    = 2'h0;
	assign OTG_CS_N    = 1'b1;
	assign OTG_DACK0_N = 1'b1;
	assign OTG_DACK1_N = 1'b1;
	assign OTG_FSPEED  = 1'b1;
	assign OTG_DATA    = 16'hzzzz;
	assign OTG_LSPEED  = 1'b1;
	assign OTG_RD_N    = 1'b1;
	assign OTG_RST_N   = 1'b1;
	assign OTG_WR_N    = 1'b1;

	assign SD_DAT = 1'bz;
	assign SD_CLK = 1'b0;
   
	//Disable all other peripherals.
	//assign I2C_SCLK = 1'b0;
	assign IRDA_TXD = 1'b0;
	//assign TD_RESET = 1'b0;
	assign TDO = 1'b0;
	assign UART_TXD = 1'b0;
   
	assign LEDR[9:0] = CCD_DATA;
   
	assign	reset = ~KEY[3];

	assign	TD_RESET	=	1'b1;	//	Allow 27 MHz input

/*----------------------- CCD module -------------------------*/
	//	CCD
	wire	[9:0]	CCD_DATA;
	wire			CCD_SDAT;
	wire			CCD_SCLK;
	wire			CCD_FLASH;
	wire			CCD_FVAL;
	wire			CCD_LVAL;
	wire			CCD_PIXCLK;
	reg				CCD_MCLK;	//	CCD Master Clock

	wire	[15:0]	Read_DATA1;
	wire	[15:0]	Read_DATA2;

	wire	[9:0]	mCCD_DATA;
	wire			mCCD_DVAL;
	wire			mCCD_DVAL_d;
	wire	[10:0]	X_Cont;
	wire	[10:0]	Y_Cont;
	wire	[9:0]	X_ADDR;
	wire	[31:0]	Frame_Cont;
	wire	[9:0]	mCCD_R;
	wire	[9:0]	mCCD_G;
	wire	[9:0]	mCCD_B;
	wire			DLY_RST_0;
	wire			DLY_RST_1;
	wire			DLY_RST_2;
	wire			Read;
	reg		[9:0]	rCCD_DATA;
	reg				rCCD_LVAL;
	reg				rCCD_FVAL;
	wire	[9:0]	sCCD_R;
	wire	[9:0]	sCCD_G;
	wire	[9:0]	sCCD_B;
	wire			sCCD_DVAL;

	//	For Sensor 1
	assign	CCD_DATA[0]	=	GPIO_1[0];
	assign	CCD_DATA[1]	=	GPIO_1[1];
	assign	CCD_DATA[2]	=	GPIO_1[5];
	assign	CCD_DATA[3]	=	GPIO_1[3];
	assign	CCD_DATA[4]	=	GPIO_1[2];
	assign	CCD_DATA[5]	=	GPIO_1[4];
	assign	CCD_DATA[6]	=	GPIO_1[6];
	assign	CCD_DATA[7]	=	GPIO_1[7];
	assign	CCD_DATA[8]	=	GPIO_1[8];
	assign	CCD_DATA[9]	=	GPIO_1[9];
	assign	GPIO_1[11]	=	CCD_MCLK;
	assign	GPIO_1[15]	=	CCD_SDAT;
	assign	GPIO_1[14]	=	CCD_SCLK;
	assign	CCD_FVAL	=	GPIO_1[13];
	assign	CCD_LVAL	=	GPIO_1[12];
	assign	CCD_PIXCLK	=	GPIO_1[10];
	
Reset_Delay_CCD		u2	(	
							.iCLK(CLOCK_50),
							.iRST(KEY[0]),
							.oRST_0(DLY_RST_0),
							.oRST_1(DLY_RST_1),
							.oRST_2(DLY_RST_2)	);
	
CCD_Capture			u3	(	.oDATA(mCCD_DATA),
							.oDVAL(mCCD_DVAL),
							.oX_Cont(X_Cont),
							.oY_Cont(Y_Cont),
							.oFrame_Cont(Frame_Cont),
							.iDATA(rCCD_DATA),
							.iFVAL(rCCD_FVAL),
							.iLVAL(rCCD_LVAL),
							.iSTART(!KEY[3]),
							.iEND(!KEY[2]),
							.iCLK(CCD_PIXCLK),
							.iRST(DLY_RST_1)	);

RAW2RGB				u4	(	.oRed(mCCD_R),
							.oGreen(mCCD_G),
							.oBlue(mCCD_B),
							.oDVAL(mCCD_DVAL_d),
							.iX_Cont(X_Cont),
							.iY_Cont(Y_Cont),
							.iDATA(mCCD_DATA),
							.iDVAL(mCCD_DVAL),
							.iCLK(CCD_PIXCLK),
							.iRST(DLY_RST_1)	);
							
SEG7_LUT_8 			u5	(	.oSEG0(HEX0),.oSEG1(HEX1),
							.oSEG2(HEX2),.oSEG3(HEX3),
							.oSEG4(HEX4),.oSEG5(HEX5),
							.oSEG6(HEX6),.oSEG7(HEX7),
							.iDIG(Frame_Cont) );
							
Sdram_Control_4Port	u6	(	//	HOST Side
						    .REF_CLK(CLOCK_50),
						    .RESET_N(1'b1),
							//	FIFO Write Side 1
						    .WR1_DATA(	{sCCD_G[9:5],
										 sCCD_B[9:0]}),
							.WR1(sCCD_DVAL),
							.WR1_ADDR(0),
							.WR1_MAX_ADDR(640*512),
							.WR1_LENGTH(9'h100),
							.WR1_LOAD(!DLY_RST_0),
							.WR1_CLK(CCD_PIXCLK),
							//	FIFO Write Side 2
						    .WR2_DATA(	{sCCD_G[4:0],
										 sCCD_R[9:0]}),
							.WR2(sCCD_DVAL),
							.WR2_ADDR(22'h100000),
							.WR2_MAX_ADDR(22'h100000+640*512),
							.WR2_LENGTH(9'h100),
							.WR2_LOAD(!DLY_RST_0),
							.WR2_CLK(CCD_PIXCLK),
							//	FIFO Read Side 1
						    .RD1_DATA(Read_DATA1),
				        	.RD1(Read),
				        	.RD1_ADDR(640*16),
							.RD1_MAX_ADDR(640*496),
							.RD1_LENGTH(9'h100),
				        	.RD1_LOAD(!DLY_RST_0),
							.RD1_CLK(VGA_CTRL_CLK),
							//	FIFO Read Side 2
						    .RD2_DATA(Read_DATA2),
				        	.RD2(Read),
				        	.RD2_ADDR(22'h100000+640*16),
							.RD2_MAX_ADDR(22'h100000+640*496),
							.RD2_LENGTH(9'h100),
				        	.RD2_LOAD(!DLY_RST_0),
							.RD2_CLK(VGA_CTRL_CLK),
							//	SDRAM Side
						    .SA(DRAM_ADDR),
						    .BA({DRAM_BA_1,DRAM_BA_0}),
						    .CS_N(DRAM_CS_N),
						    .CKE(DRAM_CKE),
						    .RAS_N(DRAM_RAS_N),
				            .CAS_N(DRAM_CAS_N),
				            .WE_N(DRAM_WE_N),
						    .DQ(DRAM_DQ),
				            .DQM({DRAM_UDQM,DRAM_LDQM}),
							.SDR_CLK(DRAM_CLK)	);

I2C_CCD_Config 		u7	(	//	Host Side
							.iCLK(CLOCK_50),
							.iRST_N(KEY[1]),
							.iExposure(16'd3072),
							//	I2C Side
							.I2C_SCLK(CCD_SCLK),
							.I2C_SDAT(CCD_SDAT)	);

Mirror_Col			u8	(	//	Input Side
							.iCCD_R(mCCD_R),
							.iCCD_G(mCCD_G),
							.iCCD_B(mCCD_B),
							.iCCD_DVAL(mCCD_DVAL_d),
							.iCCD_PIXCLK(CCD_PIXCLK),
							.iRST_N(DLY_RST_1),
							//	Output Side
							.oCCD_R(sCCD_R),
							.oCCD_G(sCCD_G),
							.oCCD_B(sCCD_B),
							.oCCD_DVAL(sCCD_DVAL));

always@(posedge CLOCK_50)	CCD_MCLK	<=	~CCD_MCLK;

always@(posedge CCD_PIXCLK)
begin
	rCCD_DATA	<=	CCD_DATA;
	rCCD_LVAL	<=	CCD_LVAL;
	rCCD_FVAL	<=	CCD_FVAL;
end
/*--------------------------- end ----------------------------*/


/*--------------------- log LUT module -----------------------*/
	wire [9:0] LR,LG,LRGBmax,L1,L2;
	assign L1 = LG + LRGBmax;
	assign L2 = LR - LG + LRGBmax;

log_rom_table lrt_r (CCD_PIXCLK,Read_DATA2[9:0],LR);
log_rom_table lrt_g (CCD_PIXCLK,{Read_DATA1[14:10],Read_DATA2[14:10]},LG);
log_rom_table lrt_rgbmax (CCD_PIXCLK,10'd1023,LRGBmax);
/*--------------------------- end ----------------------------*/


/*-------------------- Spatial averager ----------------------*/
	wire [9:0] r2;
	wire r3;
	assign r3 = (r2 > 10'd256);	// thresholding
	wire r;	 	// manually picked value to threshold L1 and L2
	assign r = ((L1 == 10'b0010000000)||(L2 == 10'b0001100100))?1'd1:1'd0;

average av1(.out(r2),
			.in(r?10'd1023:10'd0), 
			.dk_const(4'd4),
			.clk(CCD_PIXCLK));
/*--------------------------- end ----------------------------*/


/*--------------------- Down sampling ------------------------*/
	reg [39:0] down_sample[0:29]; 	// down sample 30x40 register array
	reg [5:0] xsum;
	reg [5:0] ysum[39:0];			// a running sum array each over its 16 vertical pixels 
	wire xavg;						
	assign xavg = (xsum > 6'd0);	// thresholded xsum value, 1 if greater than 0

always @ (posedge VGA_CTRL_CLK) begin
	if (Coord_X[3:0] != 4'd15)
		xsum <= xsum + r3;		// adding spatial weighted average value to the xsum
	else
	begin
		if (Coord_Y[3:0] != 4'd15)	// within 16 rows
			ysum[Coord_X[9:4]] <= ysum[Coord_X[9:4]] + xavg; // add up xsum to get ysum
		else
		begin
			ysum[Coord_X[9:4]] <= 6'd0;	// reset ysum for next 16 rows
			down_sample[Coord_Y[9:4]][Coord_X[9:4]] <= (ysum[Coord_X[9:4]] > 6'b000111); // update and threshold down sampled array
		end
		xsum <= 6'd0;		// reset xsum for next 16 columns
	end
end
/*--------------------------- end ----------------------------*/


/*------------------- Finding centriod -----------------------*/
	reg [5:0] countx,county;	// coordniate in our 30x40 array
	reg [31:0] m00, m01, m10, area;	// finding center of mass (COM), area

	wire [11:0] atempout;
	reg [11:0] atempin;

	// time weighted average to smooth out blob size transition
	average av4(.out(atempout),
				.in(atempin), 
				.dk_const(4'd1),
				.clk(VGA_CTRL_CLK));

	wire [5:0] tempm10;			// m10 = sum( x if f(x,y)=1 else 0) of all x,y
	assign tempm10 = (down_sample[county][countx]) ? countx:6'd0;
	wire [5:0] tempm01;			// m01 = sum( y if f(x,y)=1 else 0) of all x,y
	assign tempm01 = (down_sample[county][countx]) ? county:6'd0;

	reg [5:0] xbar,ybar, xbar1, ybar1;	// COM in x and y
	wire [5:0] xbartmp, ybartmp;
	assign xbartmp = m10/m00;
	assign ybartmp = m01/m00;

always @ (posedge VGA_CTRL_CLK)
begin
	if (reset)
	begin
		countx <= 6'd0;
		county <= 6'd0;
		m00 <= 32'd1;	// make sure m00 is never 0
		m10 <= 32'd0;
		m01 <= 32'd0;
	end

	//modify display during sync
	else if ((~VGA_VS | ~VGA_HS))  		// sync is active low; 
	begin
		if(~VGA_VS)		// update offsets and depth info when screen refreshes
		begin
			if ((xbar1 != 0) && (ybar1 != 0)) 
			begin
				xbar <= xbar1;		
				ybar <= ybar1;
				area <= {20'd0,atempout};
			end
		end
		else
		begin
			if (county < 6'd30)
			begin
				if (countx < 6'd40)
				begin
					m00 <= m00 + down_sample[county][countx];
					m10 <= m10 + tempm10;	// sum of tempm10 over whole down_sample array
					m01 <= m01 + tempm01;	// sum of tempm01 over whole down_sample array
					countx <= countx + 6'd1;
				end
				else	// prepare for next row
				begin
					countx <= 6'd0;
					county <= county + 6'd1;
				end
			end
			else	// reset every register for new screen
			begin
				atempin <= m00[11:0];
				xbar1 <= xbartmp;
				ybar1 <= ybartmp;
				countx <= 6'd0;
				county <= 6'd0;
				m00 <= 32'd1;
				m10 <= 32'd0;
				m01 <= 32'd0;
			end
		end
	end
end
/*--------------------------- end ----------------------------*/


/*------------------- Centriod averager ----------------------*/
	wire [5:0] xbaravg, ybaravg;
	
average av2(.out(xbaravg),
			.in(xbar), 
			.dk_const(4'd1),
			.clk(VGA_CTRL_CLK));
			
average av3(.out(ybaravg),
			.in(ybar), 
			.dk_const(4'd1),
			.clk(VGA_CTRL_CLK));		
/*--------------------------- end ----------------------------*/


/*------------------ Shortest path plotter -------------------*/	
	wire [8:0] xofftemp, yofftemp;
	assign xoff = xofftemp - 9'd160;
	assign yoff = yofftemp - 9'd120;
	
counter	count1(
			.iclk(VGA_CTRL_CLK),
			.ireset(reset),
			.ispeed(13'b1111100000000),
			.iHS(VGA_HS),
			.iVS(VGA_VS),
			.iendx({xbaravg,3'd0}),
			.iendy({ybaravg,3'd0}),
			.oxoffset(xofftemp),
			.oyoffset(yofftemp)
			);
/*--------------------------- end ----------------------------*/


/*------------- Nios II projection calculation ---------------*/
	reg offsetrdy;
	reg [8:0] xoffset, yoffset;
	wire coordrdy;
	wire [17:0]	b1,b2,b3,b4,b5,b6,b7,b8;
	wire [8:0] xoff, yoff;

projection p(
                    // 1) global signals:
                     .clk(CLOCK_50),
                     .reset_n(1),
                    // the_B1
                     .out_port_from_the_B1(b1),
                    // the_B2
                     .out_port_from_the_B2(b2),
                    // the_B3
                     .out_port_from_the_B3(b3),
                    // the_B4
                     .out_port_from_the_B4(b4),
                    // the_B5
                     .out_port_from_the_B5(b5),
                    // the_B6
                     .out_port_from_the_B6(b6),
                    // the_B7
                     .out_port_from_the_B7(b7),
                    // the_B8
                     .out_port_from_the_B8(b8),
                    // the_RESET
                     .in_port_to_the_RESET(reset),
                    // the_XOFF
                     .in_port_to_the_XOFF(xoffset),
                    // the_YOFF
                     .in_port_to_the_YOFF(yoffset),
                    // the_goIN
                     .in_port_to_the_goIN(offsetrdy),
                    // the_goOUT
                     .out_port_from_the_goOUT(coordrdy),
                    // the_AREA
					 .in_port_to_the_AREA(area)		 );
/*--------------------------- end ----------------------------*/			

			
/*----------------- Bresenham line module -------------------*/
line	line1(
			.iX1(x1),
			.iY1(y1),
			.iX2(x2),
			.iY2(y2),
			.iclk(VGA_CTRL_CLK),
			.ireset(reset),
			.iFLAG(linedrawing|lineerasing),
			.ipixeldone(pixeldone),
			.iHS(VGA_HS),
			.iVS(VGA_VS),
			.icolor(color),
			.oaddr_reg(addr_regline1),
			.odata_reg(data_regline1),
			.odoneflag(doneflag1),
			.opixelflag(pixelflag1)
			);		
/*--------------------------- end ----------------------------*/	


/*-------------------- Main state machine	------------------*/

	//state machine variables
	wire	reset;
	(* preserve *)reg	[3:0]	state;		// state machine
	reg	[17:0]	addr_reg;	// memory address register for SRAM
	reg	[15:0]	data_reg;	// memory data register  for SRAM
	wire [17:0]	addr_regline1;	// memory address register from line.v for SRAM
	wire [15:0]	data_regline1;	// memory data register from line.v for SRAM
	wire doneflag1;			// asserted when a line is done drawing from line.v
	wire pixelflag1;		// asserted when a pixel coordinate info is availiable from line.v
	reg	pixeldone;			// flag to indicate a pixel is saved in SRAM
	reg linedrawing, lineerasing;	// determine during drawing or erasing
	reg [15:0] color;		// color reg

	reg lock;				// get the correct address and data for SRAM
	reg	we;					// write enable for SRAM

	reg [8:0] x1, y1;		// begin point x and y for a line
	reg [8:0] x2, y2;		// end point x and y for a line
	reg [3:0] lineon;		// which line is currently processing

	// Temp registers x and y 
	reg [8:0] x1_0, y1_0, x1_1, y1_1, x1_2, y1_2, x1_3, y1_3;
	reg [8:0] x1_4, y1_4, x1_5, y1_5, x1_6, y1_6, x1_7, y1_7;
	reg [8:0] x1_8, y1_8, x1_9, y1_9, x1_10, y1_10, x1_11, y1_11;

	reg [8:0] x2_0, y2_0, x2_1, y2_1, x2_2, y2_2, x2_3, y2_3;
	reg [8:0] x2_4, y2_4, x2_5, y2_5, x2_6, y2_6, x2_7, y2_7;
	reg [8:0] x2_8, y2_8, x2_9, y2_9, x2_10, y2_10, x2_11, y2_11;

	//state names
	parameter	init	= 4'd0,
				draw1	= 4'd1,
				draw2	= 4'd2,
				draw3	= 4'd3,
				draw4	= 4'd4,
				pause	= 4'd5,
				erase1	= 4'd6,
				draw1_1 = 4'd7,
				erase1_1 = 4'd8;

always @ (posedge VGA_CTRL_CLK)
begin	
		
	if (reset)		//synch reset assumes KEY0 is held down 1/60 second
	begin
		addr_reg <= {Coord_X[9:1],Coord_Y[9:1]} ;	// [17:0]
		we <= 1'b0;				// write some memory
		data_reg <= 16'b0;		// write all zeros (black)
		
		color <= 16'h0000;
		lineon <= 4'd0;			// start drawing from the 0th line
		offsetrdy <= 1'd1;		// enable nios II to calculate projection coordnitate

		yoffset <= yoff;		// update offset
		xoffset <= xoff;
		state <= init; 
	end

	//modify display during sync
	else if ((~VGA_VS | ~VGA_HS))  		// sync is active low; 
	begin
		case(state)			
			init: begin
				x1 <= 9'd160+b5[17:9];
				x2 <= 9'd160+b6[17:9];
				y1 <= 9'd120-b5[8:0];
				y2 <= 9'd120-b6[8:0];
				color <= 16'h555f;
				x1_0 <= 9'd160+b5[17:9];
				x2_0 <= 9'd160+b6[17:9];
				y1_0 <= 9'd120-b5[8:0];
				y2_0 <= 9'd120-b6[8:0];
				
				we <= 1'b1;
				linedrawing <= 1'd0;	// turn off line.v
				lineerasing <=1'd0;		// turn off line.v
				pixeldone <= 1'd0;
				
				state <= draw1;						
			end
			
			draw1: begin
				we <= 1'b1;
				pixeldone <= 1'd0;
				linedrawing <= 1'd1;		// turn on line.v
				
				if (doneflag1)				// if a line coord info is ready
				begin
					if (lineon == 4'd12)	// all lines drawn
					begin
						lineon <= 4'd0;
						state <= pause;		// wait for coord change
					end
					else					// draw next line
					begin
						offsetrdy <= 1'd0;	// turn off nios II
						state <= draw1_1;
					end
					linedrawing <= 1'd0;
				end
				else if (pixelflag1)		// if a pixel info is ready
				begin
					state <= draw2;
				end
			end
			
			draw1_1: begin
				if(lineon != 4'd12) begin
					lineon <= lineon+4'd1;	
					// circulates through all lines and save a copy
					case (lineon)
						8:	begin
							x1 <= 9'd160+b1[17:9];
							x2 <= 9'd160+b2[17:9];
							y1 <= 9'd120-b1[8:0];
							y2 <= 9'd120-b2[8:0];
							color <= 16'hffff;
							x1_8 <= 9'd160+b1[17:9];
							x2_8 <= 9'd160+b2[17:9];
							y1_8 <= 9'd120-b1[8:0];
							y2_8 <= 9'd120-b2[8:0];
						end
						9:	begin
							x1 <= 9'd160+b2[17:9];
							x2 <= 9'd160+b3[17:9];
							y1 <= 9'd120-b2[8:0];
							y2 <= 9'd120-b3[8:0];
							color <= 16'hffff;
							x1_9 <= 9'd160+b2[17:9];
							x2_9 <= 9'd160+b3[17:9];
							y1_9 <= 9'd120-b2[8:0];
							y2_9 <= 9'd120-b3[8:0];
						end
						10:	begin
							x1 <= 9'd160+b3[17:9];
							x2 <= 9'd160+b4[17:9];
							y1 <= 9'd120-b3[8:0];
							y2 <= 9'd120-b4[8:0];
							color <= 16'hffff;
							x1_10 <= 9'd160+b3[17:9];
							x2_10 <= 9'd160+b4[17:9];
							y1_10 <= 9'd120-b3[8:0];
							y2_10 <= 9'd120-b4[8:0];
						end
						11:	begin
							x1 <= 9'd160+b4[17:9];
							x2 <= 9'd160+b1[17:9];
							y1 <= 9'd120-b4[8:0];
							y2 <= 9'd120-b1[8:0];
							color <= 16'hffff;
							x1_11 <= 9'd160+b4[17:9];
							x2_11 <= 9'd160+b1[17:9];
							y1_11 <= 9'd120-b4[8:0];
							y2_11 <= 9'd120-b1[8:0];
						end
						4:	begin
							x1 <= 9'd160+b1[17:9];
							x2 <= 9'd160+b5[17:9];
							y1 <= 9'd120-b1[8:0];
							y2 <= 9'd120-b5[8:0];
							color <= 16'haaaf;
							x1_4 <= 9'd160+b1[17:9];
							x2_4 <= 9'd160+b5[17:9];
							y1_4 <= 9'd120-b1[8:0];
							y2_4 <= 9'd120-b5[8:0];
						end
						5:	begin
							x1 <= 9'd160+b2[17:9];
							x2 <= 9'd160+b6[17:9];
							y1 <= 9'd120-b2[8:0];
							y2 <= 9'd120-b6[8:0];
							color <= 16'haaaf;
							x1_5 <= 9'd160+b2[17:9];
							x2_5 <= 9'd160+b6[17:9];
							y1_5 <= 9'd120-b2[8:0];
							y2_5 <= 9'd120-b6[8:0];
						end
						6:	begin
							x1 <= 9'd160+b3[17:9];
							x2 <= 9'd160+b7[17:9];
							y1 <= 9'd120-b3[8:0];
							y2 <= 9'd120-b7[8:0];
							color <= 16'haaaf;
							x1_6 <= 9'd160+b3[17:9];
							x2_6 <= 9'd160+b7[17:9];
							y1_6 <= 9'd120-b3[8:0];
							y2_6 <= 9'd120-b7[8:0];
						end
						7:	begin
							x1 <= 9'd160+b4[17:9];
							x2 <= 9'd160+b8[17:9];
							y1 <= 9'd120-b4[8:0];
							y2 <= 9'd120-b8[8:0];
							color <= 16'haaaf;
							x1_7 <= 9'd160+b4[17:9];
							x2_7 <= 9'd160+b8[17:9];
							y1_7 <= 9'd120-b4[8:0];
							y2_7 <= 9'd120-b8[8:0];
						end
						0:	begin
							x1 <= 9'd160+b5[17:9];
							x2 <= 9'd160+b6[17:9];
							y1 <= 9'd120-b5[8:0];
							y2 <= 9'd120-b6[8:0];
							color <= 16'h555f;
							x1_0 <= 9'd160+b5[17:9];
							x2_0 <= 9'd160+b6[17:9];
							y1_0 <= 9'd120-b5[8:0];
							y2_0 <= 9'd120-b6[8:0];
						end
						1:	begin
							x1 <= 9'd160+b6[17:9];
							x2 <= 9'd160+b7[17:9];
							y1 <= 9'd120-b6[8:0];
							y2 <= 9'd120-b7[8:0];
							color <= 16'h555f;
							x1_1 <= 9'd160+b6[17:9];
							x2_1 <= 9'd160+b7[17:9];
							y1_1 <= 9'd120-b6[8:0];
							y2_1 <= 9'd120-b7[8:0];
						end
						2:	begin
							x1 <= 9'd160+b7[17:9];
							x2 <= 9'd160+b8[17:9];
							y1 <= 9'd120-b7[8:0];
							y2 <= 9'd120-b8[8:0];
							color <= 16'h555f;
							x1_2 <= 9'd160+b7[17:9];
							x2_2 <= 9'd160+b8[17:9];
							y1_2 <= 9'd120-b7[8:0];
							y2_2 <= 9'd120-b8[8:0];
						end
						3:	begin
							x1 <= 9'd160+b8[17:9];
							x2 <= 9'd160+b5[17:9];
							y1 <= 9'd120-b8[8:0];
							y2 <= 9'd120-b5[8:0];
							color <= 16'h555f;
							x1_3 <= 9'd160+b8[17:9];
							x2_3 <= 9'd160+b5[17:9];
							y1_3 <= 9'd120-b8[8:0];
							y2_3 <= 9'd120-b5[8:0];
						end	
					endcase			
				end
				else
				begin
					x1 <= x1_0;
					x2 <= x2_0;
					y1 <= y1_0;
					y2 <= y2_0;
				end
				
				state <= draw1;
			end
			
			erase1_1: begin
				if(lineon != 4'd12) begin
					lineon <= lineon+4'd1;
					// circulates through all lines and use the copy
					case (lineon)
						8:	begin
							x1 <= x1_8;
							x2 <= x2_8;
							y1 <= y1_8;
							y2 <= y2_8;
							color <= 16'd0;
						end
						9:	begin
							x1 <= x1_9;
							x2 <= x2_9;
							y1 <= y1_9;
							y2 <= y2_9;
							color <= 16'd0;
						end
						10:	begin
							x1 <= x1_10;
							x2 <= x2_10;
							y1 <= y1_10;
							y2 <= y2_10;
							color <= 16'd0;
						end
						11:	begin
							x1 <= x1_11;
							x2 <= x2_11;
							y1 <= y1_11;
							y2 <= y2_11;
							color <= 16'd0;
						end
						4:	begin
							x1 <= x1_4;
							x2 <= x2_4;
							y1 <= y1_4;
							y2 <= y2_4;
							color <= 16'd0;
						end
						5:	begin
							x1 <= x1_5;
							x2 <= x2_5;
							y1 <= y1_5;
							y2 <= y2_5;
							color <= 16'd0;
						end
						6:	begin
							x1 <= x1_6;
							x2 <= x2_6;
							y1 <= y1_6;
							y2 <= y2_6;
							color <= 16'd0;
						end
						7:	begin
							x1 <= x1_7;
							x2 <= x2_7;
							y1 <= y1_7;
							y2 <= y2_7;
							color <= 16'd0;
						end
						0:	begin
							x1 <= x1_0;
							x2 <= x2_0;
							y1 <= y1_0;
							y2 <= y2_0;
							color <= 16'd0;
						end
						1:	begin
							x1 <= x1_1;
							x2 <= x2_1;
							y1 <= y1_1;
							y2 <= y2_1;
							color <= 16'd0;
						end
						2:	begin
							x1 <= x1_2;
							x2 <= x2_2;
							y1 <= y1_2;
							y2 <= y2_2;
							color <= 16'd0;
						end
						3:	begin
							x1 <= x1_3;
							x2 <= x2_3;
							y1 <= y1_3;
							y2 <= y2_3;
							color <= 16'd0;
						end		
					endcase		
				end
				else
				begin
					x1 <= x1_0;
					x2 <= x2_0;
					y1 <= y1_0;
					y2 <= y2_0;
				end
				
				state <= erase1;
			end
			
			pause: begin	// wait for any coordinate changes from projection calculation
				we <= 1'b1;
				yoffset <= yoff;	// update new offsets
				xoffset <= xoff;
				offsetrdy <= 1'd1;	// turn on nios II
				if  ((coordrdy == 1'd1) &&
					((x1_0 != 9'd160+b5[17:9]) || (x2_0 != 9'd160+b6[17:9]) ||
					(y1_0 != 9'd120-b5[8:0])  || (y2_0 != 9'd120-b6[8:0])  ||
					(x1_1 != 9'd160+b6[17:9]) || (x2_1 != 9'd160+b7[17:9]) ||
					(y1_1 != 9'd120-b6[8:0])  || (y2_1 != 9'd120-b7[8:0])  ||
					(x1_2 != 9'd160+b7[17:9]) || (x2_2 != 9'd160+b8[17:9]) ||
					(y1_2 != 9'd120-b7[8:0])  || (y2_2 != 9'd120-b8[8:0])  ||
					(x1_3 != 9'd160+b8[17:9]) || (x2_3 != 9'd160+b5[17:9]) ||
					(y1_3 != 9'd120-b8[8:0])  || (y2_3 != 9'd120-b5[8:0])  ||
					(x1_4 != 9'd160+b1[17:9]) || (x2_4 != 9'd160+b5[17:9]) ||
					(y1_4 != 9'd120-b1[8:0])  || (y2_4 != 9'd120-b5[8:0])  ||
					(x1_5 != 9'd160+b2[17:9]) || (x2_5 != 9'd160+b6[17:9]) ||
					(y1_5 != 9'd120-b2[8:0])  || (y2_5 != 9'd120-b6[8:0])  ||
					(x1_6 != 9'd160+b3[17:9]) || (x2_6 != 9'd160+b7[17:9]) ||
					(y1_6 != 9'd120-b3[8:0])  || (y2_6 != 9'd120-b7[8:0])  ||
					(x1_7 != 9'd160+b4[17:9]) || (x2_7 != 9'd160+b8[17:9]) ||
					(y1_7 != 9'd120-b4[8:0])  || (y2_7 != 9'd120-b8[8:0])  ||
					(x1_8 != 9'd160+b1[17:9]) || (x2_8 != 9'd160+b2[17:9]) ||
					(y1_8 != 9'd120-b1[8:0])  || (y2_8 != 9'd120-b2[8:0])  ||
					(x1_9 != 9'd160+b2[17:9]) || (x2_9 != 9'd160+b3[17:9]) ||
					(y1_9 != 9'd120-b2[8:0])  || (y2_9 != 9'd120-b3[8:0])  ||
					(x1_10 != 9'd160+b3[17:9]) || (x2_10 != 9'd160+b4[17:9]) ||
					(y1_10 != 9'd120-b3[8:0])  || (y2_10 != 9'd120-b4[8:0])  ||
					(x1_11 != 9'd160+b4[17:9]) || (x2_11 != 9'd160+b1[17:9]) ||
					(y1_11 != 9'd120-b4[8:0])  || (y2_11 != 9'd120-b1[8:0])))
				begin
					state <= erase1;	// erasing starts
					color <= 16'd0;
					pixeldone <= 1'd0;
					offsetrdy <= 1'd0;
				end
			end
			
			erase1: begin
				we <= 1'b1;
				pixeldone <= 1'd0;
				lineerasing <= 1'd1;	// enable line.v for erasing
				offsetrdy <= 1'd0;		// turn off nios II
				
				if (doneflag1)				// if a line coord info is ready
				begin
					if (lineon == 4'd12)	// all lines erased
					begin
						lineon <= 4'd0;		// repeat
						state <= init;
					end
					else					// erase next line
					begin
						state <= erase1_1;
					end
					lineerasing <= 1'd0;
				end
				else if (pixelflag1)		// if a pixel info is ready
				begin
					state <= draw2;
				end
			end
			
			draw2: begin
				lock <= 1'b1;			// set the interlock to detect end of sync interval
				addr_reg <= addr_regline1;
				we <= 1'b1;				// no memory write
				state <= draw3;
			end
			
			draw3: begin
				if (lock)
				begin
					we <= 1'b0;			// write enable (active low)
					data_reg <= data_regline1;	// write to SRAM
					pixeldone <= 1'd1;
					state <= draw4;
				end
				else
				begin
					we <= 1'b1;
					state <= draw2;
				end
			end
			
			draw4:
			begin				
				if (linedrawing)		// go back to line drawing scheme
				begin
					state <= draw1;
				end
				else if (lineerasing)	// go back to line erasing scheme
				begin
					state <= erase1;
				end
				else
					state <= erase1;
			end						
		endcase
	end
	//show display when not blanking, 
	//which implies we=1 (not enabled); and use VGA module address
	else
	begin
		lock <= 1'b0; 		// clear lock if display starts because this destroys mem addr_reg
		addr_reg <= {Coord_X[9:1],Coord_Y[9:1]};	// gives VGA module the control of SRAM
		we <= 1'b1;
	end
end
/*--------------------------- end ----------------------------*/


/*--------------------------- SRAM ---------------------------*/
	// SRAM_control
	assign	SRAM_ADDR = addr_reg;
	assign	SRAM_DQ = (we)? 16'hzzzz : data_reg ;
	assign	SRAM_UB_N = 0;			// hi byte select enabled
	assign	SRAM_LB_N = 0;			// lo byte select enabled
	assign	SRAM_CE_N = 0;			// chip is enabled
	assign	SRAM_WE_N = we;			// write when ZERO
	assign	SRAM_OE_N = 0;			// output enable is overidden by WE

	// Show SRAM on the VGA	( SW[0] for toggle between cube perspective view and face tracking result )
	assign	mVGA_R = SW[0]?{SRAM_DQ[15:12],6'd0}:(((Coord_X[9:1]==(xofftemp))&(Coord_Y[9:1]==(yofftemp)))?10'd0:((down_sample[Coord_Y[9:4]][Coord_X[9:4]])||((Coord_Y[9:4]==ybaravg)&&(Coord_X[9:4]==xbaravg))?10'd1023:10'd0));
	assign	mVGA_G = SW[0]?{SRAM_DQ[11:8],6'd0}:(((Coord_X[9:1]==(xofftemp))&(Coord_Y[9:1]==(yofftemp)))?10'd1023:(down_sample[Coord_Y[9:4]][Coord_X[9:4]]?((Coord_Y[9:4]==ybaravg)&&(Coord_X[9:4]==xbaravg)?10'd0:10'd1023):10'd0));
	assign	mVGA_B = SW[0]?{SRAM_DQ[7:4],6'd0}:(((Coord_X[9:1]==(xofftemp))&(Coord_Y[9:1]==(yofftemp)))?10'd0:(down_sample[Coord_Y[9:4]][Coord_X[9:4]]?((Coord_Y[9:4]==ybaravg)&&(Coord_X[9:4]==xbaravg)?10'd0:10'd1023):10'd0));
/*--------------------------- end ----------------------------*/


/*------------------------ VGA output ------------------------*/
	wire			VGA_CTRL_CLK;
	wire			AUD_CTRL_CLK;
	wire	[9:0]	mVGA_R;
	wire	[9:0]	mVGA_G;
	wire	[9:0]	mVGA_B;
	wire	[19:0]	mVGA_ADDR;		// video memory address
	wire	[9:0]	Coord_X, Coord_Y;	// display coords
	wire			DLY_RST;

VGA_Audio_PLL 	p1(	
					.areset(~DLY_RST_0),
					.inclk0(CLOCK_27),
					.c0(VGA_CTRL_CLK),
					.c1(AUD_CTRL_CLK),
					.c2(VGA_CLK)		);


VGA_Controller	u1(	//	Host Side
					.iCursor_RGB_EN(4'b0111),
					.oAddress(mVGA_ADDR),
					.oCoord_X(Coord_X),
					.oCoord_Y(Coord_Y),
					.iRed(mVGA_R),
					.iGreen(mVGA_G),
					.iBlue(mVGA_B),
					//	VGA Side
					.oRequest(Read),
					.oVGA_R(VGA_R),
					.oVGA_G(VGA_G),
					.oVGA_B(VGA_B),
					.oVGA_H_SYNC(VGA_HS),
					.oVGA_V_SYNC(VGA_VS),
					.oVGA_SYNC(VGA_SYNC),
					.oVGA_BLANK(VGA_BLANK),
					//	Control Signal
					.iCLK(VGA_CTRL_CLK),
					.iRST_N(DLY_RST_0)	);
/*--------------------------- end ----------------------------*/
endmodule

/*------------------- Bruce Land's module --------------------*/
/////////////////////////////////////////////////////
//// Time weighted average amplitude (2'comp) ///////
/////////////////////////////////////////////////////
// dk_const    e-folding time of average			         
// 3			~8 samples
// 4			16 
// 5			32
// 6			64
// 7			128 -- 2.7 mSec at 48kHz
// 8			256 -- 5.3 mSec (useful for music/voice)
// 9			512 -- 10.5 mSec (useful for music/voice)
// 10			1024 -- 21 mSec (useful for music/voice)
// 11			2048 -- 42 mSec
module average (out, in, dk_const, clk);

	output reg signed [11:0] out ;
	input wire signed [11:0] in ;
	input wire [3:0] dk_const ;
	input wire clk;
	
	wire signed  [13:0] new_out ;
	//first order lowpass of absolute value of input
	assign new_out = out - (out>>>(dk_const)) + ((in[11]?-in:in)>>>dk_const) ;
	
	always @(posedge clk)
	begin
		 out <= new_out ;
	end
endmodule
/*--------------------------- end ----------------------------*/
